package com.ms.player;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.HashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ms.game.common.OSType;
import com.ms.game.common.container.LevelInfoBinUtil;
import com.ms.game.itembox.Item;
import com.ms.game.itembox.ItemBox;
import com.ms.service.module.analysis.PlatformType;
import com.xpec.c4.db.dao.PlayerLevelCalculator;
import com.xpec.c4.db.dto.DTManualTransfer;
import com.xpec.c4.game.character.PeriodSyncStatisInfo;
import com.xpec.c4.game.common.Helper;
import com.xpec.c4.game.datamanager.agent.money.CoinType;
import com.xpec.c4.game.time.TimeSys;
import com.xpec.c4.game.utility.GUID;
import com.xpec.c4.service.module.common.PlayerCommonInfoManager;

public class Player implements Serializable {
	private static final long serialVersionUID = -823296672106059356L;

	private static final Log log = LogFactory.getLog(Player.class);

	// 不存入 db 的資料

	/** sessionID */
	private GUID sessionID = null;

	/** 心跳消息處理，加速器檢查 */
	private PeriodSyncStatisInfo syncStatisInfo = null;

	/** 管理變更過的屬性清單 */
	private UpdateAttributeList updateAttributeList = new UpdateAttributeList();

	/** 管理變更過的道具清單 */
	private UpdateItemList updateItemList = new UpdateItemList();

	/** 是否是認證會員 */
	private boolean verifiedMember = false;

	/** 是否有設定銀行密碼 */
	private boolean haveBankPassword = false;

	/** 是否正在等待 dc 處理資料 */
	private boolean dcQuery = false;

	/** 同帳號是否有首儲角色了 */
	private boolean haveFirstStoreCharacter = false;

	/** 角色是否透過h5登入 */
	private boolean h5Status = false;

	/** h5 agent 回傳資料時用的參數 (json) */
	private String agentData = "";

	/** 暫存的 {@link #agentData} 實體 */
	private transient AgentData agentDataInstance = null;

	// 要存入 db 的資料

	/*
	 * <pre>
	 * 自身id
	 * UUID先不支援 Utility的copy , 原寫法沒檢查type, 會強迫給職結果爛掉, 與其讓她每次檢查class type不如先標記
	 * 
	 * @see com.ms.game.db.util.Utility
	 * </pre>
	 */
	@DTManualTransfer
	private GUID guid = null;

	/** 帳戶id */
	@DTManualTransfer
	private GUID accountId = null;

	/** 營運商accountID */
	private String cooperatorAccountId = "";

	/** 名稱 */
	private String name = "";

	/** 頭像 */
	private String facephoto = "";

	/** 性別 1 男 0 女 */
	private boolean gender = false;

	/** 等级 */
	private int level = 0;

	/** 經驗 */
	private BigDecimal exp = BigDecimal.ZERO;

	/** 道具箱 */
	private ItemBox itemBox = new ItemBox();

	/** 金幣 */
	private BigDecimal goldCoin = BigDecimal.ZERO;

	/** 試玩幣 */
	private BigDecimal trialCoin = BigDecimal.ZERO;

	/** 幸運金 */
	private BigDecimal luckyCoin = BigDecimal.ZERO;

	/** 銀行金幣 */
	private BigDecimal bankGoldCoin = BigDecimal.ZERO;

	/** 暫存錢包的錢 */
	private BigDecimal tmpCash = BigDecimal.ZERO;

	/** VIP等級 */
	private int vip = 0;

	/** vip累積值 */
	private long vipExp = 0;

	/** 所在的 zone id */
	private String zoneId = "";

	/** 包月到期時間 */
	@DTManualTransfer
	private long monthlyFeeEndTime = 0;

	/** 包月領取階段 0 ~ 29 個領取階段 */
	private int monthlyFeePayStage = 0;

	/** 包週到期時間 */
	@DTManualTransfer
	private long weeklyFeeEndTime = 0;

	/** 包週領取階段 0 ~ 29 個領取階段 */
	private int weeklyFeePayStage = 0;

	/** 禁言效果過期時間 */
	private long silentExpireTime = 0;

	/** 角色最近一次的登錄時間（該數據是為了配合角色退出時算出角色的在線時間） */
	@DTManualTransfer
	private long loginTime = 0;

	/** 角色創建時間 */
	@DTManualTransfer
	private long createTime = 0;

	/** 角色最後登入時間 */
	@DTManualTransfer
	private long lastloginTime = 0;

	/** 角色最後登入的IP */
	private String lastloginIP = "";

	/** 最後一次登入的平台 */
	private String lastLoginPlatform = "";

	/** 創角時的平台 */
	@DTManualTransfer
	private String registeredPlatform = "";

	/** 領取包月獎勵 */
	@DTManualTransfer
	private long monthlyAwardTime = 0;

	/** 領取包週獎勵 */
	@DTManualTransfer
	private long weeklyAwardTime = 0;

	/** 角色名稱被修改的時間 */
	@DTManualTransfer
	private long nameModifyTime = 0;

	/** 角色最近一次的離線時間 */
	@DTManualTransfer
	private long logoutTime = 0;

	/** 上次讀取時間（每次從Manager讀取时，修改为當前時間） */
	private long loadTime = 0;

	/** 是否為試玩帳號 */
	private boolean trialAccount = false;

	/** 自己的邀請碼 */
	private String inviteCode = "";

	/* 上線的邀請碼 */
	private String uplineCode = "";

	/* 上線的Id */
	private String uplineId = "";

	/** 錯誤次數 */
	private int errorTimes = 0;

	/** 5次錯誤後禁止時間 */
	private long disableTime = 0;

	/** 禮物錯誤次數 */
	private int errorTimesGift = 0;

	/** 禮物5次錯誤後禁止時間 */
	private long disableTimeGift = 0;

	/** 玩家被禁止送禮 禁止時間 */
	private long disableSendGiftTime = 0;

	/** 玩家被禁止送禮原因 */
	private String disableSendGiftReason = "";

	/** 最後一次取得自動回覆幸運金的時間 (ms) */
	private long lastGetLuckyCoinTime = 0;

	/**
	 * <pre>
	 * 跨日登入次數
	 * 距離上次登入有跨日就+1，一次跨三天也是+1
	 * </pre>
	 */
	private int continuousLoginCount = 0;

	/* 首儲獎勵連續登入天數 0等於沒有轉點過，ㄧ但轉點就從1開始算 */
	private int storeRewardContinuousLoginCount = 0;

	/** 是否為首創角色 */
	private boolean firstCreate = false;

	/** 首儲獎勵領取數量 */
	private int firstStoreReward = 0;

	/** 離限掛機結果 */
	private String offlinePlayResult = "";

	/** 使用者類型 {@link PlayerUserType} 判斷是不是機器人 0是人，1是機器人(小樂) */
	private int userType = 0;

	/** 角色名稱後的隨機碼 */
	private String nameNumber = "";

	/** 水晶 */
	private int crystal = 0;

	/** GMTOOL禁言時間 */
	private long banTalkTime = 0;

	/** 是否可產生抽傭金給上線 */
	private boolean canMakeCommission = false;

	/** 玩家身分 目前 : 0是一般玩家 1是經銷商玩家 */
	private byte playerIdentityType = 0;

	/** 玩家控制欄位 */
	private String playerSwitchList = null; // 必須是NULL, 否則在BasicZone.java:380行會跳出錯誤

	/** 上一次 使用等級寶箱的等級 */
	private int lastLevelBoxUseLevel = 0;

	/** 營運商 id */
	private String venderId = "";

	/** 子營運商 id */
	private String subVenderId = "";

	public GUID getSessionID() {
		return sessionID;
	}

	public void setSessionID(GUID sessionID) {
		this.sessionID = sessionID;
	}

	public PeriodSyncStatisInfo getSyncStatisInfo() {
		return syncStatisInfo;
	}

	public void setSyncStatisInfo(PeriodSyncStatisInfo syncStatisInfo) {
		this.syncStatisInfo = syncStatisInfo;
	}

	public boolean isVerifiedMember() {
		return verifiedMember;
	}

	public void setVerifiedMember(boolean verifiedMember) {
		this.verifiedMember = verifiedMember;
	}

	public boolean isHaveBankPassword() {
		return haveBankPassword;
	}

	public void setHaveBankPassword(boolean haveBankPassword) {
		this.haveBankPassword = haveBankPassword;
	}

	public boolean isDcQuery() {
		return dcQuery;
	}

	public void setDcQuery(boolean dcQuery) {
		this.dcQuery = dcQuery;
	}

	public boolean isHaveFirstStoreCharacter() {
		return haveFirstStoreCharacter;
	}

	public void setHaveFirstStoreCharacter(boolean haveFirstStoreCharacter) {
		this.haveFirstStoreCharacter = haveFirstStoreCharacter;
	}

	public boolean isH5Status() {
		return h5Status;
	}

	public void setH5Status(boolean h5Status) {
		this.h5Status = h5Status;
	}

	public String getAgentData() {
		return agentData;
	}

	public void setAgentData(String agentData) {
		this.agentData = agentData;
		this.agentDataInstance = null;
	}

	/**
	 * 取得轉換後的 {@link #agentData} 實體
	 */
	public AgentData getAgentDataInstance() {
		if (agentDataInstance == null) {
			agentDataInstance = AgentData.parse(agentData);
		}

		return agentDataInstance;
	}

	public GUID getGuid() {
		return guid;
	}

	public void setGuid(GUID guid) {
		this.guid = guid;
	}

	public GUID getAccountId() {
		return accountId;
	}

	public void setAccountId(GUID accountId) {
		this.accountId = accountId;
	}

	public String getCooperatorAccountId() {
		return cooperatorAccountId;
	}

	public void setCooperatorAccountId(String cooperatorAccountId) {
		this.cooperatorAccountId = cooperatorAccountId;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
		updateAttributeList.addUpdateValue(PlayerAttributeType.NAME, name);
	}

	public String getFacephoto() {
		return facephoto;
	}

	public void setFacephoto(String facephoto) {
		this.facephoto = facephoto;
	}

	public boolean isGender() {
		return gender;
	}

	public void setGender(boolean gender) {
		this.gender = gender;
	}

	public int getLevel() {
		return level;
	}

	public void setLevel(int level) {
		this.level = level;
		updateAttributeList.addUpdateValue(PlayerAttributeType.LEVEL, level);
	}

	public BigDecimal getExp() {
		return exp;
	}

	public void setExp(BigDecimal exp) {
		this.exp = exp;
		updateAttributeList.addUpdateValue(PlayerAttributeType.EXP, exp);

		HashMap<String, Long> expInfos = LevelInfoBinUtil.getExpInfos(exp);
		addUpdateExpInCurrentLevel(expInfos.get(PlayerLevelCalculator.EXP_IN_CURRENT_LEVEL));
		addUpdateExpToNextLevel(expInfos.get(PlayerLevelCalculator.EXP_TO_NEXT_LEVEL));
	}

	public ItemBox getItemBox() {
		return itemBox;
	}

	public void setItemBox(ItemBox itemBox) {
		this.itemBox = itemBox;
	}

	public BigDecimal getGoldCoin() {
		return goldCoin;
	}

	public void setgoldCoin(BigDecimal goldCoin) {
		this.goldCoin = goldCoin;
		updateAttributeList.addUpdateValue(PlayerAttributeType.GOLD_COIN, goldCoin);
	}

	public void setGoldCoinLongValue(BigDecimal goldCoin) {
		this.goldCoin = goldCoin;
		updateAttributeList.addUpdateValue(PlayerAttributeType.GOLD_COIN, this.goldCoin);
	}

	public BigDecimal getTrialCoin() {
		return trialCoin;
	}

	public void setTrialCoin(BigDecimal trialCoin) {
		this.trialCoin = trialCoin;
		updateAttributeList.addUpdateValue(PlayerAttributeType.TRIAL_COIN, trialCoin);
	}

	public BigDecimal getLuckyCoin() {
		return luckyCoin;
	}

	public void setLuckyCoin(BigDecimal luckyCoin) {
		this.luckyCoin = luckyCoin;
		updateAttributeList.addUpdateValue(PlayerAttributeType.LUCKY_COIN, luckyCoin);
	}

	public BigDecimal getBankGoldCoin() {
		return bankGoldCoin;
	}

	public void setBankGoldCoin(BigDecimal bankGoldCoin) {
		this.bankGoldCoin = bankGoldCoin;
		updateAttributeList.addUpdateValue(PlayerAttributeType.BANK_GOLD_COIN, bankGoldCoin);
	}

	public long getBankGoldCoinLongValue() {
		return bankGoldCoin.longValue();
	}

	public void setBankGoldCoin(long bankGoldCoin) {
		BigDecimal decimalGoldCoin = Helper.sub(this.bankGoldCoin, new BigDecimal(this.bankGoldCoin.longValue()));
		this.bankGoldCoin = Helper.add(new BigDecimal(bankGoldCoin), decimalGoldCoin);

		updateAttributeList.addUpdateValue(PlayerAttributeType.BANK_GOLD_COIN, this.bankGoldCoin);
	}

	public BigDecimal getTmpCash() {
		return tmpCash;
	}

	public void setTmpCash(BigDecimal tmpCash) {
		this.tmpCash = tmpCash;
	}

	public int getVip() {
		return vip;
	}

	public void setVip(int vip) {
		this.vip = vip;
		updateAttributeList.addUpdateValue(PlayerAttributeType.VIP, vip);
	}

	public long getVipExp() {
		return vipExp;
	}

	public void setVipExp(long vipExp) {
		this.vipExp = vipExp;
		updateAttributeList.addUpdateValue(PlayerAttributeType.VIP_EXP, vipExp);
	}

	public String getZoneId() {
		return zoneId;
	}

	public void setZoneId(String zoneId) {
		this.zoneId = zoneId;
	}

	public long getMonthlyFeeEndTime() {
		return monthlyFeeEndTime;
	}

	public void setMonthlyFeeEndTime(long monthlyFeeEndTime) {
		this.monthlyFeeEndTime = monthlyFeeEndTime;
		updateAttributeList.addUpdateValue(PlayerAttributeType.MONTHLY_FEE_END_TIME, monthlyFeeEndTime);
	}

	public int getMonthlyFeePayStage() {
		return monthlyFeePayStage;
	}

	public void setMonthlyFeePayStage(int monthlyFeePayStage) {
		this.monthlyFeePayStage = monthlyFeePayStage;
	}

	public long getWeeklyFeeEndTime() {
		return weeklyFeeEndTime;
	}

	public void setWeeklyFeeEndTime(long weeklyFeeEndTime) {
		this.weeklyFeeEndTime = weeklyFeeEndTime;
		updateAttributeList.addUpdateValue(PlayerAttributeType.WEEKLY_FEE_END_TIME, weeklyFeeEndTime);
	}

	public int getWeeklyFeePayStage() {
		return weeklyFeePayStage;
	}

	public void setWeeklyFeePayStage(int weeklyFeePayStage) {
		this.weeklyFeePayStage = weeklyFeePayStage;
	}

	public long getSilentExpireTime() {
		return silentExpireTime;
	}

	public void setSilentExpireTime(long silentExpireTime) {
		this.silentExpireTime = silentExpireTime;
		updateAttributeList.addUpdateValue(PlayerAttributeType.SILENT_EXPIRE_TIME, this.silentExpireTime);
	}

	public long getLoginTime() {
		return loginTime;
	}

	public void setLoginTime(long loginTime) {
		this.loginTime = loginTime;
	}

	public long getCreateTime() {
		return createTime;
	}

	public void setCreateTime(long createTime) {
		this.createTime = createTime;
	}

	public long getLastloginTime() {
		return lastloginTime;
	}

	public void setLastloginTime(long lastloginTime) {
		this.lastloginTime = lastloginTime;
	}

	public String getLastloginIP() {
		return lastloginIP;
	}

	public void setLastloginIP(String lastloginIP) {
		this.lastloginIP = lastloginIP;
	}

	public String getLastLoginPlatform() {
		return lastLoginPlatform;
	}

	public void setLastLoginPlatform(String lastLoginPlatform) {
		this.lastLoginPlatform = lastLoginPlatform;
	}

	public String getRegisteredPlatform() {
		return registeredPlatform;
	}

	public void setRegisteredPlatform(String registeredPlatform) {
		this.registeredPlatform = registeredPlatform;
	}

	public long getMonthlyAwardTime() {
		return monthlyAwardTime;
	}

	public void setMonthlyAwardTime(long monthlyAwardTime) {
		this.monthlyAwardTime = monthlyAwardTime;
		updateAttributeList.addUpdateValue(PlayerAttributeType.MONTHLY_AWARD_TIME, monthlyAwardTime);
	}

	public long getWeeklyAwardTime() {
		return weeklyAwardTime;
	}

	public void setWeeklyAwardTime(long weeklyAwardTime) {
		this.weeklyAwardTime = weeklyAwardTime;
		updateAttributeList.addUpdateValue(PlayerAttributeType.WEEKLY_AWARD_TIME, weeklyAwardTime);
	}

	public long getNameModifyTime() {
		return nameModifyTime;
	}

	public void setNameModifyTime(long nameModifyTime) {
		this.nameModifyTime = nameModifyTime;
	}

	public long getLogoutTime() {
		return logoutTime;
	}

	public void setLogoutTime(long logoutTime) {
		this.logoutTime = logoutTime;
	}

	public long getLoadTime() {
		return loadTime;
	}

	public void setLoadTime(long loadTime) {
		this.loadTime = loadTime;
	}

	public boolean isTrialAccount() {
		return trialAccount;
	}

	public void setTrialAccount(boolean trialAccount) {
		this.trialAccount = trialAccount;
	}

	public String getInviteCode() {
		return inviteCode;
	}

	public void setInviteCode(String inviteCode) {
		this.inviteCode = inviteCode;
		updateAttributeList.addUpdateValue(PlayerAttributeType.INVITE_CODE, inviteCode);
	}

	public String getUplineCode() {
		return uplineCode;
	}

	public void setUplineCode(String uplineCode) {
		this.uplineCode = uplineCode;
	}

	public String getUplineId() {
		return uplineId;
	}

	public void setUplineId(String uplineId) {
		this.uplineId = uplineId;
	}

	public int getErrorTimes() {
		return errorTimes;
	}

	public void setErrorTimes(int errorTimes) {
		this.errorTimes = errorTimes;
	}

	public long getDisableTime() {
		return disableTime;
	}

	public void setDisableTime(long disableTime) {
		this.disableTime = disableTime;
	}

	public int getErrorTimesGift() {
		return errorTimesGift;
	}

	public void setErrorTimesGift(int errorTimesGift) {
		this.errorTimesGift = errorTimesGift;
	}

	public long getDisableTimeGift() {
		return disableTimeGift;
	}

	public void setDisableTimeGift(long disableTimeGift) {
		this.disableTimeGift = disableTimeGift;
	}

	public long getDisableSendGiftTime() {
		return disableSendGiftTime;
	}

	public void setDisableSendGiftTime(long disableSendGiftTime) {
		this.disableSendGiftTime = disableSendGiftTime;
	}

	public String getDisableSendGiftReason() {
		return disableSendGiftReason;
	}

	public void setDisableSendGiftReason(String disableSendGiftReason) {
		this.disableSendGiftReason = disableSendGiftReason;
	}

	public long getLastGetLuckyCoinTime() {
		return lastGetLuckyCoinTime;
	}

	public void setLastGetLuckyCoinTime(long lastGetLuckyCoinTime) {
		this.lastGetLuckyCoinTime = lastGetLuckyCoinTime;
		updateAttributeList.addUpdateValue(PlayerAttributeType.LAST_GET_LUCKY_COIN_TIME, lastGetLuckyCoinTime);
	}

	public int getContinuousLoginCount() {
		return continuousLoginCount;
	}

	public void setContinuousLoginCount(int continuousLoginCount) {
		this.continuousLoginCount = continuousLoginCount;
	}

	public int getStoreRewardContinuousLoginCount() {
		return storeRewardContinuousLoginCount;
	}

	public void setStoreRewardContinuousLoginCount(int storeRewardContinuousLoginCount) {
		this.storeRewardContinuousLoginCount = storeRewardContinuousLoginCount;
		updateAttributeList.addUpdateValue(PlayerAttributeType.STORE_REWARD_CONTINUOUS_LOGIN_COUNT,
				storeRewardContinuousLoginCount);
	}

	public boolean isFirstCreate() {
		return firstCreate;
	}

	public void setFirstCreate(boolean firstCreate) {
		this.firstCreate = firstCreate;
	}

	public int getFirstStoreReward() {
		return firstStoreReward;
	}

	public void setFirstStoreReward(int firstStoreReward) {
		this.firstStoreReward = firstStoreReward;
	}

	public String isOfflinePlayResult() {
		return offlinePlayResult;
	}

	public void setOfflinePlayResult(String offlinePlayResult) {
		this.offlinePlayResult = offlinePlayResult;
	}

	public int getUserType() {
		return userType;
	}

	public void setUserType(int userType) {
		this.userType = userType;
	}

	public String getNameNumber() {
		return nameNumber;
	}

	public void setNameNumber(String nameNumber) {
		this.nameNumber = nameNumber;
	}

	public int getCrystal() {
		return crystal;
	}

	public void setCrystal(int crystal) {
		this.crystal = crystal;
		updateAttributeList.addUpdateValue(PlayerAttributeType.CRYSTAL, crystal);
	}

	public long getBanTalkTime() {
		return banTalkTime;
	}

	public void setBanTalkTime(long banTalkTime) {
		this.banTalkTime = banTalkTime;
	}

	public boolean isCanMakeCommission() {
		return canMakeCommission;
	}

	public void setCanMakeCommission(boolean canMakeCommission) {
		this.canMakeCommission = canMakeCommission;
	}

	public byte getPlayerIdentityType() {
		return playerIdentityType;
	}

	public void setPlayerIdentityType(byte playerIdentityType) {
		this.playerIdentityType = playerIdentityType;
	}

	public String getPlayerSwitchList() {
		return playerSwitchList;
	}

	public void setPlayerSwitchList(String playerSwitchList) {
		this.playerSwitchList = playerSwitchList;
	}

	public int getLastLevelBoxUseLevel() {
		return lastLevelBoxUseLevel;
	}

	public void setLastLevelBoxUseLevel(int lastLevelBoxUseLevel) {
		this.lastLevelBoxUseLevel = lastLevelBoxUseLevel;
	}

	public String getVenderId() {
		return venderId;
	}

	public void setVenderId(String venderId) {
		this.venderId = venderId;
	}

	public String getSubVenderId() {
		return subVenderId;
	}

	public void setSubVenderId(String subVenderId) {
		this.subVenderId = subVenderId;
	}

	// 對 player 的一些控制邏輯

	/**
	 * 取得角色名稱和後四碼合併起來的完整名稱
	 */
	public String getNameWithNumber() {
		return PlayerNickNameParser.mergeNickName(name, nameNumber);
	}

	/**
	 * <pre>
	 * 用player上面的sessionId去找出 platformType
	 * 再用platFormType 找出 OSType
	 * 如果是小樂一律提供PC版的gameList
	 * 如果回null 就是找不到OSTYPE
	 * 如果有新的PlayerUserType就要在這邊加判斷(case...)，否則就會提供全部的gameList
	 * </pre>
	 */
	public OSType getOsType() {
		OSType osType = null;
		switch (this.userType) {
		case PlayerUserType.PLAYER: { // 一般真人玩家
			String platformTypeStr = PlayerCommonInfoManager.getInstance().getLoginPlatformBySessionId(sessionID);
			PlatformType platformType = PlatformType.getENUMbyString(platformTypeStr);
			if (platformType != null) {
				osType = OSType.getOSTypeByPlatformType(platformType);
			} else {
				if (log.isErrorEnabled()) {
					log.error("can't recognize login platform, playerGUID: " + guid.toString() + ", accountID: "
							+ accountId.toString());
				}
			}
			break;
		}

		case PlayerUserType.ROBORT: {// 小樂一律提供PC版的gameList
			osType = OSType.ANDROID;
			break;
		}

		default: {// 新的PlayerUserType就要在這邊加判斷(case...)，否則就會提供全部的gameList
			break;
		}
		}

		return osType;
	}

	/**
	 * 是否是機器人
	 */
	public boolean isRobot() {
		if (userType == PlayerUserType.ROBORT) {
			return true;
		}
		return false;
	}

	/**
	 * 是否是玩家
	 */
	public boolean isPlayer() {
		if (userType == PlayerUserType.PLAYER) {
			return true;
		}
		return false;
	}

	/**
	 * 在角色身上新增道具
	 * 
	 * @param item
	 *            新道具資料
	 */
	public void addItem(Item item) {
		itemBox.addItem(item);
		updateItemList.addUpdateItem(item);
	}

	/**
	 * 設定指定道具的數量
	 * 
	 * @param itemSn
	 *            道具序號
	 * @param count
	 *            數量
	 */
	public void setItemCount(String itemSn, int count) {
		Item item = itemBox.setItemCount(itemSn, count);
		updateItemList.addUpdateItem(item);
	}

	/**
	 * 更新道具資料
	 * 
	 * @param item
	 *            有異動的道具資料
	 */
	public void updateItem(Item item) {
		itemBox.addItem(item);
		updateItemList.addUpdateItem(item);
	}

	/**
	 * 取得角色身上指定幣別的錢
	 * 
	 * @param coinType
	 *            幣別
	 * @return 指定幣跌的錢
	 */
	public BigDecimal getCoin(CoinType coinType) {
		switch (coinType) {
		case TRIAL:
			return trialCoin;
		case GOLD:
			return goldCoin;
		case LUCKY:
			return luckyCoin;
		default:
			break;
		}

		return new BigDecimal(CoinType.UNKNOW_TYPE.getId());
	}

	/**
	 * 設定角色身上指定幣別的錢
	 * 
	 * @param coinType
	 *            幣別
	 * @param value
	 *            數值
	 */
	public void setCoin(CoinType coinType, BigDecimal value) {
		switch (coinType) {
		case TRIAL:
			setTrialCoin(value);
			break;
		case GOLD:
			setGoldCoinLongValue(value);
			break;
		case LUCKY:
			setLuckyCoin(value);
			break;
		default:
			break;
		}
	}

	/**
	 * 取得一般幣(C幣+幸運金)
	 */
	public BigDecimal getNormalCoin() {
		return Helper.add(goldCoin, luckyCoin);
	}

	/**
	 * 是否有被禁止寄送禮物
	 */
	public boolean isDisableSendGift() {
		long curTime = TimeSys.currentTimeMills();

		if (disableSendGiftTime == -1) {
			return true;
		}

		if (curTime <= disableSendGiftTime) {
			return true;
		}

		return false;
	}

	/**
	 * 是否為儲值會員
	 */
	public boolean isPurchaseMember() {
		if (vip > 0) {
			return true;
		}

		return false;
	}

	/**
	 * 是否為正式會員
	 */
	public boolean isFormalMember() {
		if (level > 0) {
			return true;
		}

		return false;
	}

	/**
	 * 角色是否使用試玩幣
	 */
	public boolean isUseTrialCoin() {
		// 正式會員使用正式幣，非正式會員使用試玩幣
		if (!isFormalMember()) {
			return true;
		}

		return false;
	}

	/**
	 * 清除變更過的屬性列表
	 */
	public void clearUpdatedAttrList() {
		updateAttributeList.clear();
		updateItemList.clear();
	}

	/**
	 * 將有變更過的屬性一次送給 client
	 */
	public void sendUpdatedAttrToClient() {
		updateAttributeList.sendToClient(guid, sessionID, userType);
		updateItemList.sendToClient(guid, sessionID, userType);
	}

	/**
	 * 是否在禁言狀態
	 */
	public boolean isSilent() {
		if (TimeSys.currentTimeMills() <= silentExpireTime || TimeSys.currentTimeSec() <= banTalkTime
				|| banTalkTime == -1) {
			return true;
		}

		return false;
	}

	/**
	 * 是否被後台禁言
	 */
	public boolean isSilentByGmtool() {
		if (TimeSys.currentTimeSec() <= banTalkTime || banTalkTime == -1) {
			return true;
		}
		return false;
	}

	/**
	 * 設定禁言持續時間
	 * 
	 * @param duration
	 *            持續時間 (sec), 會覆蓋之前的設定，而不是累加
	 */
	public void setSilentDuration(long duration) {
		if (duration < 0) {
			return;
		}

		setSilentExpireTime(TimeSys.currentTimeMills() + (duration * 1000));
	}

	/**
	 * 對於角色來說登入 zone 的事件，登入後角色自己要做的事放這裡
	 * 
	 * @param zoneId
	 *            登入的 zone id
	 */
	public void onLoginZone(String zoneId) {
	}

	/**
	 * 定時觸發的 player 更新事件
	 * 
	 * @param difftime
	 *            距離上一次 update 經過的時間 (ms)
	 */
	public void onUpdate(long difftime) {
	}

	public PlayerSwitchList getPlayerSwitchListClass() {
		return PlayerSwitchList.getPlayerSwitchListClassByJsonString(this.playerSwitchList);
	}

	/**
	 * 新增當前等級經驗提供給client的資訊
	 */
	public void addUpdateExpInCurrentLevel(long expCurrentLevel) {
		updateAttributeList.addUpdateValue(PlayerAttributeType.EXP_IN_CURRENT_LEVEL, expCurrentLevel);
	}

	/**
	 * 新增下個等級需求經驗提供給client的資訊
	 */
	public void addUpdateExpToNextLevel(long expToNextLevel) {
		updateAttributeList.addUpdateValue(PlayerAttributeType.EXP_TO_NEXT_LEVEL, expToNextLevel);
	}

	@Override
	public String toString() {
		String nameStr = PlayerNickNameParser.mergeNickName(name, nameNumber);
		return nameStr + "|" + getGuid();
	}

	/**
	 * 產生 player name
	 */
	public static String makePlayerName(String ezname, String coopSn) {
		return ezname + "_" + coopSn;
	}
}